#include "file_update.h"

extern fileinfo_t file_update;
extern char path[128];
extern char md5_cmd[128]; // MD5命令缓冲区
extern ipport_t tmip;     // 初始化结构体
extern int unzip_status;

/**
 * @brief 处理文件更新
 * @param buf 接收到的JSON字符串
 * @param ac_fd TCP连接的文件描述符
 * @return 成功返回0，失败返回-1
 */
int file_handle(char buf[], int ac_fd, sqlite3 *db) // 处理文件更新
{
    char file_path[64] = "touch /home/hq/";

    cJSON *root = cJSON_Parse(buf); // 解析JSON数据
    if (root == NULL)
    {
        printf("Failed to parse JSON----------3\n");
        return -1;
    }
    cJSON *type = cJSON_GetObjectItem(root, "type"); // 获取"type"字段
    if (type->valueint == 4)                         // 用户注册
    {
        printf("Sign in = %d\n", type->valueint); // 注册
        user_sign_in(buf, ac_fd, db);
    }
    else if (type->valueint == 5) // 用户登录
    {
        printf("Login in = %d\n", type->valueint); // 登录
        user_login(buf, ac_fd, db);
    }
    else
    {
        cJSON *md5 = cJSON_GetObjectItem(root, "md5"); // 获取"md5"字段
        if (md5 == NULL)
        {
            printf("Failed to get 'md5' from JSON.\n");
            cJSON_Delete(root);
            return -1;
        }
        else
        {
            strcpy(file_update.md5, md5->valuestring); // 复制MD5值
            file_update.md5[strlen(file_update.md5)] = '\0';
            printf("%s\n", file_update.md5);
        }

        cJSON *data = cJSON_GetObjectItem(root, "data"); // 获取"data"字段
        if (data == NULL)
        {
            printf("Failed to get 'data' from JSON.\n");
            cJSON_Delete(root);
            return -1;
        }
        cJSON *ver = cJSON_GetObjectItem(data, "ver"); // 获取"ver"字段
        if (ver == NULL)
        {
            printf("Failed to get 'ver' from JSON.\n");
            cJSON_Delete(root);
            return -1;
        }
        cJSON *file_name = cJSON_GetObjectItem(data, "file_name"); // 获取"file_name"字段
        if (file_name == NULL)
        {
            printf("Failed to get 'file_name' from JSON.\n");
            cJSON_Delete(root);
            return -1;
        }
        else if (strlen(file_name->valuestring) > 0) // 如果文件名不为空
        {
            strcpy(file_update.file_name, file_name->valuestring); // 复制文件名
            file_update.file_name[strlen(file_update.file_name)] = '\0';
            printf("File update request received: %s\n", file_name->valuestring);
            strcat(file_path, file_update.file_name); // 拼接文件名
        }

        if (!strcmp(tmip.version, ver->valuestring)) // 比较版本号
        {
            printf("Version is the same, no update needed.\n");
            cJSON *new = cJSON_CreateObject();
            cJSON_AddNumberToObject(new, "type", 1);                       // 添加"type"字段
            cJSON_AddItemToObject(new, "update", cJSON_CreateBool(FALSE)); // 添加"update"字段
            char *json_data = cJSON_Print(new);                            // 将JSON对象转换为字符串

            if (send(ac_fd, json_data, strlen(json_data), 0) < 0) // 发送
            {
                perror("err: send");
                close(ac_fd);
                return -1;
            }
            cJSON_Delete(root);
            cJSON_Delete(new); // 正确释放整个JSON树
            free(json_data);   // 释放cJSON_Print分配的内存
        }
        else
        {
            cJSON *new = cJSON_CreateObject();
            cJSON_AddNumberToObject(new, "type", 1);                      // 添加"type"字段
            cJSON_AddItemToObject(new, "update", cJSON_CreateBool(TRUE)); // 添加"update"字段
            char *json_data = cJSON_Print(new);                           // 将JSON对象转换为字符串

            if (send(ac_fd, json_data, strlen(json_data), 0) < 0) // 发送
            {
                perror("err: send");
                close(ac_fd);
                return -1;
            }
            pthread_t tid;
            if (pthread_create(&tid, NULL, (void *)pthread_handler, NULL) != 0)
            {
                perror("err: pthread_create");
                return -1;
            }
            pthread_join(tid, NULL);
            memset(tmip.version, 0, sizeof(tmip.version));
            strcpy(tmip.version, ver->valuestring);
            cJSON_ReplaceItemInObject(root, "ver", cJSON_CreateString(tmip.version));
            char *p = cJSON_Print(root);
            FILE * fp = fopen(_PATH, "w"); // 打开配置文件
            fwrite(p, 1, strlen(p), fp); // 写入配置文件
            fclose(fp); // 关闭配置文件
            cJSON_Delete(root);
            cJSON_Delete(new); // 正确释放整个JSON树
            free(json_data);   // 释放cJSON_Print分配的内存
        }
    }
}

/**
 * @brief 线程处理函数
 * @return 返回NULL
 */
void *pthread_handler(void *arg) // 线程处理函数
{
    char unzip_cmd[128] = "";            // 增大缓冲区
    strcat(path, file_update.file_name); // 拼接文件名
    snprintf(md5_cmd, sizeof(md5_cmd), "md5sum %s", path);
    // 正确拼接解压命令
    snprintf(unzip_cmd, sizeof(unzip_cmd), "unzip %s", path);

    FILE *fp;
    int ac_fd;
    if ((fp = fopen(path, "wb")) == NULL) // 用二进制模式写入
    {
        perror("err: fopen");
        return NULL;
    }

    int tcp_fd = socket(AF_INET, SOCK_STREAM, 0); // 创建
    if (tcp_fd < 0)
    {
        perror("err: socket");
        return NULL;
    }

    struct sockaddr_in sock_t, sock_c; // 指定网络信息
    sock_t.sin_family = AF_INET;
    sock_t.sin_port = htons(pthread_port);
    sock_t.sin_addr.s_addr = INADDR_ANY;
    if (bind(tcp_fd, (struct sockaddr *)&sock_t, sizeof(sock_t)) < 0) // 绑定
    {
        perror("err: bind");
        return NULL;
    }
    printf("bind ok\n");

    if (listen(tcp_fd, 6) < 0) // 监听
    {
        perror("err: listen");
        return NULL;
    }
    printf("listen ok\n");

    char buff[512] = ""; // 接收数据缓冲区
    int len = sizeof(sock_c);
    printf("等待客户端连接...\n"); // 等待客户端连接提示

    if ((ac_fd = accept(tcp_fd, (struct sockaddr *)&sock_c, &len)) < 0) // 接受链接
    {
        perror("err: accept");
        return NULL;
    }
    printf("accept ok\n");

    while (1)
    {
        ssize_t r = recv(ac_fd, buff, sizeof(buff), 0); // 接收数据
        if (r <= 0)
        {
            perror("err: recv");
            close(ac_fd);
            break;
        }
        else
        {
            fwrite(buff, 1, r, fp); // 写入文件
            memset(buff, 0, sizeof(buff));
        }
    }
    printf("recv over\n");
    fclose(fp);
    if (strlen(file_update.file_name) > 0)
    {
        printf("File update request received: %s\n", file_update.file_name);
        system_cmd(unzip_cmd);              // 解压文件
        unzip_status = system_cmd(md5_cmd); // 计算MD5
    }
    return NULL;
}

/**
 * @brief 执行系统命令
 * @param format 格式化字符串
 * @return 成功返回0，失败返回-1
 */
int system_cmd(const char *format, ...)
{
    va_list arg;
    pid_t status;
    char cmd[MAX_CMD_SZ];

    va_start(arg, format);
    vsprintf(cmd, format, arg);
    va_end(arg);
    status = system(cmd);
    if (-1 == status || !WIFEXITED(status) || 0 != WEXITSTATUS(status))
    {
        printf("[%s]: FAIL", cmd);
        return -1;
    }
    else
    {
        return 0;
    }
}

int callback_sign(void *data, int argc, char **argv, char **azColName)
{
    int *found = (int *)data;
    *found = 1; // 设置标志表示找到了记录
    return 0;
}

int callback_login(void *data, int argc, char **argv, char **azColName)
{
    int *found = (int *)data;
    *found = 1; // 设置标志表示找到了记录
    printf("login success\n");
    return 0;
}

int user_sign_in(char buf[], int ac_fd, sqlite3 *db)
{
    char *errmsg = NULL;
    char sql[128] = "";  // 增大SQL缓冲区
    int user_exists = 0; // 用于标识用户是否存在

    cJSON *signin = cJSON_CreateObject();
    cJSON_AddItemToObject(signin, "type", cJSON_CreateNumber(4));

    cJSON *root = cJSON_Parse(buf);
    if (!root)
    {
        fprintf(stderr, "JSON parse error\n");
        return -1;
    }
    cJSON *request = cJSON_GetObjectItem(root, "request");
    cJSON *account = cJSON_GetObjectItem(request, "account");
    cJSON *password = cJSON_GetObjectItem(request, "password");
    if (!account || !password)
    {
        cJSON_Delete(root);
        return -1;
    }

    // 查询用户是否存在
    snprintf(sql, sizeof(sql), "SELECT * FROM user_manage WHERE account='%s'",
             account->valuestring);

    if (sqlite3_exec(db, sql, callback_sign, &user_exists, &errmsg) != SQLITE_OK)
    {
        fprintf(stderr, "Query error: %s\n", errmsg);
        sqlite3_free(errmsg);
        cJSON_Delete(root);
        return -1;
    }

    if (user_exists)
    {
        // 用户已存在，不能重复注册
        printf("User already exists\n");
        cJSON_AddItemToObject(signin, "signin", cJSON_CreateBool(FALSE));
    }
    else
    {
        // 用户不存在，可以注册
        memset(sql, 0, sizeof(sql));
        snprintf(sql, sizeof(sql),
                 "INSERT INTO user_manage (account, password) VALUES ('%s', '%s')",
                 account->valuestring, password->valuestring);

        if (sqlite3_exec(db, sql, NULL, NULL, &errmsg) != SQLITE_OK)
        {
            fprintf(stderr, "Insert error: %s\n", errmsg);
            sqlite3_free(errmsg);
            sqlite3_close(db);
            cJSON_Delete(root);
            return -1;
        }

        printf("User registration successful\n");
        cJSON_AddItemToObject(signin, "signin", cJSON_CreateBool(TRUE));
    }

    // 发送注册结果
    char *json_data = cJSON_Print(signin);
    if (send(ac_fd, json_data, strlen(json_data), 0) < 0)
    {
        perror("Send error");
        free(json_data);
        cJSON_Delete(signin);
        cJSON_Delete(root);
        return -1;
    }

    // 清理资源
    free(json_data);
    cJSON_Delete(signin);
    cJSON_Delete(root);
    return 0;
}

int user_login(char buf[], int ac_fd, sqlite3 *db)
{
    char *errmsg = NULL;
    char sql[128] = "";  // 增大SQL缓冲区
    int user_exists = 0; // 用于标识用户是否存在

    cJSON *login = cJSON_CreateObject();
    cJSON_AddItemToObject(login, "type", cJSON_CreateNumber(5));

    cJSON *root = cJSON_Parse(buf);
    if (root == NULL)
    {
        fprintf(stderr, "JSON parse error\n");
        return -1;
    }
    cJSON *request = cJSON_GetObjectItem(root, "request");
    cJSON *account = cJSON_GetObjectItem(request, "account");
    cJSON *password = cJSON_GetObjectItem(request, "password");
    if (!account || !password)
    {
        cJSON_Delete(root);
        return -1;
    }

    snprintf(sql, sizeof(sql), "SELECT * FROM user_manage WHERE account='%s' and password='%s'",
             account->valuestring, password->valuestring);

    sqlite3_exec(db, sql, callback_login, &user_exists, &errmsg);

    if (!user_exists)
    {
        printf("User does not exist\n");
        cJSON_AddItemToObject(login, "login", cJSON_CreateBool(FALSE));
    }
    else
    {
        printf("User exists\n");
        cJSON_AddItemToObject(login, "login", cJSON_CreateBool(TRUE));
    }

    char *json_data = cJSON_Print(login);
    if (send(ac_fd, json_data, strlen(json_data), 0) < 0)
    {
        perror("err: send");
        close(ac_fd);
        return -1;
    }
    free(json_data);
    cJSON_Delete(login);
    cJSON_Delete(root);
    return 0;
}